-module(l2_parser).
-include("protocol.hrl").
-behaviour(gen_server).
-export([start/0,init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3]).

-export([parse/3,do/1]).
-define(SERVER,?MODULE).
-record(l2_counter,{
		packet_counter = 0,
		unicast_counter = 0,
		ip_counter = 0,
		unknown_counter = 0
		}).
		
parse(Packet,Size,Context) ->
	gen_server:cast(?SERVER,{packet_comming,Packet,Size,Context}).
do(stop) ->
	gen_server:call(?SERVER,stop);
do(report) ->
	Counter = gen_server:call(?SERVER,report),
	io:format("L2 Counter ~n ~p ~n",[Counter]);
do(reset_counter) ->
	gen_server:call(?SERVER,reset_counter).
	
start()  ->
	case gen_server:start({local, ?SERVER}, ?MODULE, [], []) of 
	{ok,_} ->
		ok;
	{error,{already_started,Pid}} ->
		ok;
	{error,Reason} ->
		io:format("start ~s service failure with ~p~n",[?SERVER,Reason])
	end.
init(_) ->
	io:format("l2_parser start...~n"),
	{ok,{runing,#l2_counter{}}}.
	
handle_call({packet_comming,Packet,Size,Context},_,{runing,Counter}) ->
	case Packet of
	<<S_MAC:48,D_MAC:48,16#0800:16,IP_Packet/bytes>> ->
		packet_dispatch:do(ip_packet,{IP_Packet,Size - 14,[#l2_protocol{source_mac=S_MAC,dest_mac=D_MAC} | Context]}),
		{reply,ok,{runing,Counter#l2_counter{unicast_counter = Counter#l2_counter.unicast_counter + 1,
									   ip_counter = Counter#l2_counter.ip_counter + 1,
									   packet_counter = Counter#l2_counter.packet_counter + 1}}};
	_ ->
		{reply,{error,unknow},{runing,Counter#l2_counter{unknown_counter = Counter#l2_counter.unknown_counter + 1,
									   packet_counter = Counter#l2_counter.packet_counter + 1}}}
	end;
	
handle_call(report,_,{State,Counter}) ->
	{reply,Counter,{State,Counter}};

handle_call(reset_counter,_,{State,Counter}) ->
	{noreply,{State,#l2_counter{}}};
handle_call(stop,_,{_,Counter}) ->
	{stop,caller_initiative,{stop,Counter}};
	
handle_call(_,_,State) ->
	{reply, {error,"no func define"}, State}.
	
handle_cast({packet_comming,Packet,Size},{runing,Counter}) ->
	case Packet of
	<<S_MAC:48,D_MAC:48,16#0800:16,IP_Packet/bytes>> ->
		packet_dispatch:do(ip_packet,{IP_Packet,Size - 14}),
		{noreply,{runing,Counter#l2_counter{unicast_counter = Counter#l2_counter.unicast_counter + 1,
									   ip_counter = Counter#l2_counter.ip_counter + 1,
									   packet_counter = Counter#l2_counter.packet_counter + 1}}};
	_ ->
		{noreply,{runing,Counter#l2_counter{unknown_counter = Counter#l2_counter.unknown_counter + 1,
									   packet_counter = Counter#l2_counter.packet_counter + 1}}}
	end;
	
handle_cast(_, State) ->
	{noreply,State}.
handle_info(_, State) ->
	{noreply,State}.
terminate(_, _) ->
	ok.
code_change(_, State, _) ->
	{ok,State}.	
		